package com.nulldev.util.threading.v3_extensions;

import com.nulldev.util.java.ReflectionUtils;

public abstract class Task<T> implements _Task {
	
	public static final Void VOID = (Void) ReflectionUtils.createInstance("java.lang.Void");
	
	private volatile T result = null;
	private volatile TaskStatus status = TaskStatus.QUEUED;

	public abstract T run();
	
	@Override
	public T _run() {
		this.status = TaskStatus.RUNNING;
		try {
			this.result = this.run();
			this.status = TaskStatus.COMPLETED;
		}catch (Throwable t) {
			this.result = null;
			this.status = TaskStatus.FAILED;
			throw new RuntimeException(t);
		}
		return this.result;
	}
	
	/**
	 * Executes the task. <br>
	 * WARNING: This shouldn't be touched, this will freeze the calling thread.
	 */
	public void execute() {
		this.result = this._run();
	}

	/**
	 * Freezes the current thread until either the following occur: <br>
	 * - The task completes and returns the result. <br>
	 * - The task fails, is killed and NULL is returned.
	 */
	@Override
	public T waitTillCompletion() {
		while (true) {
			if (this.status == TaskStatus.FAILED || this.status == TaskStatus.KILLED) {
				return null;
			}else if (this.status == TaskStatus.COMPLETED) {
				break;
			}
		}
		return this.result;
	}

	@Override
	public TaskStatus status() {
		return this.status;
	}

	@Override
	public boolean completed() {
		return this.status == TaskStatus.COMPLETED;
	}

	@Override
	public T result() {
		return this.result;
	}

	/**
	 * Attempts to kill the executing thread.
	 */
	public void kill() {
		this.status = TaskStatus.KILLED;
		Thread.currentThread().interrupt();
	};

}
